#pragma once

#include <future>
#include <optional>
#include <string>
#include <tuple>

namespace hyperex::Synchronizer {
using std::future_status;
using std::nullopt;
using std::optional;
using std::promise;
using std::string;
using std::tuple;
template <class T> class Synchronizer {
public:
  auto wait(int64_t timeout) -> tuple<optional<string>, T> {
    T t;
    auto f = _promise.get_future();
    auto status =
        f.wait_for(std::chrono::duration<int, std::ratio<1>>(timeout));
    if (status == future_status::timeout) {
      return {"timeout", std::move(t)};
    } else if (status == future_status::ready) {
      return {std::nullopt, f.get()};
    } else {
      return {"unknow reason", std::move(t)};
    }
  }
  void signal(T t) { _promise.set_value(t); }

private:
  promise<T> _promise;
};
} // namespace hyperex::Synchronizer